package generadorDescriptores.dom;

import generadorDescriptores.AttributesData;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

public class XmlDocument {
	
	private Document document;
	private JoinsDom joins = null;
	private FacttableDom facttable;
	
	public XmlDocument(){
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null; 
		try {
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		DOMImplementation impl = builder.getDOMImplementation();
		this.document = impl.createDocument(null, "bi", null);
	}
	
	public Document getDocument(){
		return this.document;
	}
	
	public void setDocument(Document doc){
		this.document = doc;
	}
	
	private void setNameRoot(String nameRoot){
		document.getDocumentElement().setAttribute("name", nameRoot);
	}
	
	private void setLabelRoot(String labelRoot){
		document.getDocumentElement().setAttribute("label", labelRoot);
	}
	
	private void setPrivilege(String privilege){
		document.getDocumentElement().setAttribute("privilege", privilege);
	}
	
	/**
	 * This method will be invoked from the ui.
	 * @param name
	 * @param label
	 */
	public void setAttributes(String name, String label, String privilege){
		this.setNameRoot(name);
		this.setLabelRoot(label);
		this.setPrivilege(privilege);
	}

	public void addFacttable(FacttableDom facttable){
		this.facttable = facttable;
		this.document.getDocumentElement().appendChild(facttable.getElement());
	}
	
	public void buildDescriptorAndFacttable(AttributesData data){
		this.setAttributes(data.getBiName(), data.getBiLabel(), data.getBiPrivilege());
		FacttableDom fact = new FacttableDom(document);
		fact.setAttributes(data.getFacttableTable(), data.getMetric(), data.getFacttableType(), data.getFormatter());
		if(data.getCurrencyType()!=null){
			fact.setCurrencyType(data.getCurrencyType());
		}
		this.addFacttable(fact);
	}
	
	
	
	public static void serialize(Document doc){
		OutputFormat format = new OutputFormat(doc);
		format.setIndenting(true);
		format.setIndent(4);
		format.setStandalone(false);
		format.setEncoding("iso-8859-1");
		FileOutputStream file = null;
		try {
			file = new FileOutputStream(".\\descriptors\\descriptorGenerado.xml");
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		XMLSerializer serializer = new XMLSerializer(file, format);
		try {
			serializer.serialize(doc);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public DimensionsDom addTagDimensions(){
		NodeList list = this.document.getElementsByTagName("facttable");
		Element facttable = (Element) list.item(0);
		DimensionsDom dimensions = new DimensionsDom(this.document);
		facttable.appendChild(dimensions.getElement());
		return dimensions;
	}
	
	private Element getDimensionByName(String dimensionName, Element dimensions){
		Element dim = null;
		NodeList list = dimensions.getElementsByTagName("dimension");
		for(int i=0; i<list.getLength(); i++){
			if (list.item(i).getAttributes().getNamedItem("name").getNodeValue().equals(dimensionName)){
				dim = (Element) list.item(i); 
				
			}
		}
		return dim;
	}
	
	private Element addDimension(Element dimensions, String name){
		DimensionDom dim = new DimensionDom(document);
		dim.setAttributes(name);
		dimensions.appendChild(dim.getElement());
		return dim.getElement();
	}
	
	public void addPropertyToDimension(AttributesData data, String dimensionName){
		Element dimensions; 
		Element dimension = null;
		if(document.getElementsByTagName("dimensions").getLength()==0){
			dimensions = this.addTagDimensions().getElement();
		}
		else{
			dimensions = (Element) this.document.getElementsByTagName("dimensions").item(0);
		}

		dimension = this.getDimensionByName(dimensionName, dimensions);
		if (dimension == null){
			dimension = this.addDimension(dimensions, data.getDimensionName());
		}
				
		DimensionPropertyDom prop = new DimensionPropertyDom(this.document);
		prop.setAttributes(data);
		dimension.appendChild((Node) prop.getElement());
	}
	
	public JoinsDom addTagJoins(){
		NodeList list = this.document.getElementsByTagName("facttable");
		Element facttable = (Element) list.item(0);
		JoinsDom joins = new JoinsDom(this.document);
		facttable.appendChild(joins.getElement());
		this.joins = joins;
		return joins;
	} 
	

	public void addConditionToJoin(String joinName, AttributesData data){
		if(this.joins == null){
			this.joins = this.addTagJoins();
		}
		this.joins.addConditionToJoin(joinName, data);
	}
	
	public static String DocumentToString(Document doc){  
		StringBuilder stringBuilder = null;
	 	try {
	 	ByteArrayOutputStream stream = 
	 	new ByteArrayOutputStream();
	 	OutputFormat outputformat = new OutputFormat();
	 	outputformat.setIndent(4);
	 	outputformat.setIndenting(true);
	 	outputformat.setPreserveSpace(false);
	 	outputformat.setEncoding("iso-8859-1");
	 	XMLSerializer serializer = new XMLSerializer();
	 	serializer.setOutputFormat(outputformat);
	 	serializer.setOutputByteStream(stream);
	 	serializer.asDOMSerializer();
	 	serializer.serialize(doc.getDocumentElement());

	 	stringBuilder = new StringBuilder(stream.toString());
	 	} catch (Exception except) {
	 	except.getMessage();
	 	}
	 	return stringBuilder.toString();
		
	}
	
	public static Document stringToDocument(String s)  
	{  
	    Document tmpX=null;  
	    DocumentBuilder builder = null;  
	    try{  
	        builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();  
	    }catch(javax.xml.parsers.ParserConfigurationException error){  
	        return null;  
	    }  
	    try{  
	        tmpX=builder.parse(new ByteArrayInputStream(s.getBytes()));  
	    }catch(org.xml.sax.SAXException error){  
	        return null;  
	    }catch(IOException error){  
	        return null;  
	    }  
	    return tmpX;  
	} 
	
	
	
	
}
